<template>
  <div class="accordion">
    <div class="accordion-item" v-for="item in data" :key="item.key">
      <h2 class="accordion-header">
        <button class="accordion-button" :class="{collapsed: !item._visible}" type="button" @click="clickItem(item)">
          {{item.title}}
        </button>
      </h2>
      <div class="accordion-collapse" :class="{collapse: !item._collapsing,collapsing: item._collapsing,show: item._show}" 
        @transitionend="transitionend(item)" :style="{height: item._height}"
      >
        <div class="accordion-body" v-if="item.content" v-html="item.content" :ref="(v) => {item._accordionBody = v}">
        </div>
        <div class="accordion-body" v-else :ref="(v) => {item._accordionBody = v}">
          <slot :name="item.contentSlotName" :item='item'></slot>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang='ts'>
import { nextTick,onMounted,PropType,ref, watch } from 'vue';
import { UPDATE_MODEL_EVENT } from '../../utils/constants';
interface TransitionAttrs {
  _visible: boolean,
  _collapsing: boolean,
  _show: boolean,
  _accordionBody: HTMLElement | null,
  _height: string
}
interface AccordionAttrs {
  title: string,
  content?: string,
  contentSlotName?: string,
  key: string | number,
  [name: string]: any
}
type AccordionItem = AccordionAttrs & TransitionAttrs;

export default {
  name: 'VbAccordion',
  props: {
    data : {type: Array as PropType<Array<AccordionItem>>,default(){return [];}},
    singleSelect : {type: Boolean,default: false},
    modelValue: {type: Array as PropType<Array<string | number>>,default(){return [];}},
  },
  emits: [UPDATE_MODEL_EVENT],
  setup(props: any,ctx) {
    const activeKeys = ref<Array<string | number>>([]);
    watch(() => props.modelValue,(v) => {
      setActiveKeys(v.slice(0));
    });
    function setActiveKeys(_activeKeys: Array<string | number>,isEmit?: boolean){
      activeKeys.value = _activeKeys;
      props.data.forEach((item: AccordionItem) => {
        if(_activeKeys.indexOf(item.key) === -1){
          toggleItem(item,false);
        }else{
          toggleItem(item,true);
        }
      });
      isEmit && ctx.emit(UPDATE_MODEL_EVENT,_activeKeys);
    }
    function toggleKey(key: string | number,isRemove: boolean){
      const newKeys = activeKeys.value.slice(0);
      if(isRemove){
        for(let i=0,ii=newKeys.length;i<ii;i++){
          if(newKeys[i] === key){
            newKeys.splice(i,1);
            break;
          }
        }
      }else{
        newKeys.push(key);
      }
      setActiveKeys(newKeys,true);
    }
    function toggleItem(item: AccordionItem,visible?: boolean){
      if(visible !== undefined && !!item._visible === visible) return;
      if(item._visible){
        item._collapsing = true;
        item._show = false;
        if(item._accordionBody){
          item._height = item._accordionBody.offsetHeight + 'px';
        }
        nextTick(() => {
          //TODO 这里要reflow一下 暂时不懂
          item._accordionBody?.offsetHeight;
          item._height = '0px';
        });
      }else{
        item._collapsing = true;
        nextTick(() => {
          if(item._accordionBody){
            item._height = item._accordionBody.offsetHeight + 'px';
          }
        });
      }
      item._visible = !item._visible;
    }
    function clickItem(item: AccordionItem){
      if(props.singleSelect){
        if(item._visible){
          activeKeys.value = [];
          setActiveKeys([],true);
        }else{
          setActiveKeys([item.key],true);
        }
      }else{
        toggleKey(item.key,item._visible);
      }
    }
    onMounted(() => {
      if(props.modelValue.length > 0){
        setActiveKeys(props.modelValue.slice(0));
      }
    });
    return {
      clickItem,
      transitionend(item: AccordionItem){
        item._collapsing = false;
        item._height = '';
        if(item._visible){
          item._show = true;
        }
      }
    };
  }
};
</script>